package com.xfzp.d3;

import java.nio.ShortBuffer;

/**
 * 
 * @author AndroidApe
 * @version 2011-11-14
 */
public class Ray {
	private Coord origin;
	private Coord direction;

	public Ray() {
	}

	/**
	 * @param origin
	 *            射线原点
	 * @param direction
	 *            射线方向
	 */
	public Ray(Coord origin, Coord direction) {
		this.origin = origin;
		this.direction = direction;
	}

	/**
	 * 计算射线一的点坐标
	 * 
	 * @param t
	 * @return
	 */
	public Coord count(float t) {
		return origin.addition(direction.scalar(t));
	}

	/**
	 * 求射线与三角形的交点。没有交点时返回NULL
	 * 
	 * @param c0
	 * @param c1
	 * @param c2
	 * @return
	 */
	public Float intersectTriangle(Coord c0, Coord c1, Coord c2) {
		Coord ori = this.getOrigin();
		Coord dir = this.getDirection();

		Coord e1 = c1.subtract(c0);
		Coord e2 = c2.subtract(c0);
		Coord p = dir.cross(e2);
		float det = e1.dot(p);
		if (det > -0.0001f && det < 0.0001f)// 浮点数和0的比较，一般不用 == 0的方式，因为计算结果可能有误差
			return null;

		Coord t;
		if (det > 0) {
			t = ori.subtract(c0);
		} else {
			t = c0.subtract(ori);
			det = -det;
		}
		float u = t.dot(p);
		if (u < 0 || u > det)
			return null;

		Coord q = t.cross(e1);
		float v = dir.dot(q);
		if (v < 0 || u + v > det)
			return null;

		return e2.dot(q) / det;
	}

	/**
	 * 如果此射线与指定的形状相交，则返回拾取对象；否则返回NULL
	 * 
	 * @param shape
	 * @return
	 */
	public Picker pick(Shape shape) {
		ShortBuffer sb = shape.indexBuffer();
		Float f = null;
		Float f2;
		short face = -1;
		short i = -1;
		while (sb.hasRemaining()) {
			i++;
			f2 = intersectTriangle(shape.v(sb.get()), shape.v(sb.get()),
					shape.v(sb.get()));
			if (f2 != null) {
				if (f == null || f2 < f) {
					f = f2;
					face = i;
				}
			}
		}
		if (f != null) {
			return new Picker(f, face);
		}
		return null;
	}

	/**
	 * 返回射线原点
	 * 
	 * @return
	 */
	public Coord getOrigin() {
		return origin;
	}

	/**
	 * 设置射线原点
	 * 
	 * @param origin
	 */
	public void setOrigin(Coord origin) {
		this.origin = origin;
	}

	/**
	 * 返回射线方向
	 * 
	 * @return
	 */
	public Coord getDirection() {
		return direction;
	}

	/**
	 * 设置射线方向
	 * 
	 * @param direction
	 */
	public void setDirection(Coord direction) {
		this.direction = direction;
	}

	public class Picker {
		public final float range;// 射线原点距相交点的距离
		public final short index;// 相交的面在形状中面的集合的索引

		private Picker(float range, short index) {
			this.range = range;
			this.index = index;
		}
	}
}
